import * as DEFAULT from "@/utils/graph/default";
// import { Node } from "@/utils/graph/Node";
// import { Link } from "@/utils/graph/Link";
// import { Type } from "@/utils/graph/Type";

export function HistoryManager(ctx) {

  let context = ctx;

  let rememberStateEnum = {
    START:0, //开始记录 尚未插入当前批次第一个记录
    GOING:1, //正在记录 当前批次第一个记录已插入
    LEISURE:2 //空闲 当前没有进行记录
  }

  let rememberState = rememberStateEnum.LEISURE;

  this.operationEnum = {
    ADD_NODE: "add_node",
    EDIT_NODE: "edit_node",
    DELETE_NODE: "delete_node",
    ADD_LINK: "add_link",
    EDIT_LINK: "edit_link",
    DELETE_LINK: "delete_link",
    ADD_TYPE: "add_type",
    EDIT_TYPE: "edit_type",
    DELETE_TYPE: "delete_type"
  }

  let _this = this;
  let operationMapFun = {
    [_this.operationEnum.ADD_NODE]:withdrawAddNode,
    [_this.operationEnum.EDIT_NODE]:withdrawEditNode,
    [_this.operationEnum.DELETE_NODE]:withdrawDeleteNode,
    [_this.operationEnum.ADD_LINK]:withdrawAddLink,
    [_this.operationEnum.EDIT_LINK]:withdrawEditLink,
    [_this.operationEnum.DELETE_LINK]:withdrawDeleteLink,
    [_this.operationEnum.ADD_TYPE]:withdrawAddType,
    [_this.operationEnum.EDIT_TYPE]:withdrawEditType,
    [_this.operationEnum.DELETE_TYPE]:withdrawDeleteType,
  }

  /**---------------------------------------------------------------------------
   * 初始化历史队列
   */
  this.initHistoryList = function() {
    if(context.kgInfo.historyList) return;
    context.kgInfo.historyList = [];
    context.kgInfo.maxHistoryCount = DEFAULT.MAX_HISTORY_COUNT;
  }

  /**---------------------------------------------------------------------------
   * 添加历史记录
   */
  this.push = function(historyItem){
    let historyList = context.kgInfo.historyList;
    if(historyList.length > context.kgInfo.maxHistoryCount){
      historyList.splice(historyList.length-1,1);
    }
    historyList.unshift(historyItem);
    this.informHistoryUpdate();
  }

  /**---------------------------------------------------------------------------
   * 查看最近一条历史记录
   */
  this.look = function() {
    let historyList = context.kgInfo.historyList;
    return historyList[0];
  }

  /**---------------------------------------------------------------------------
   * 弹出最后一条历史记录
   */
  this.pop = function() {
    let historyList = context.kgInfo.historyList;
    if(historyList.length==0) return null;
    let result = historyList[0];
    historyList.splice(0,1);
    this.informHistoryUpdate();
    return result;
  }

  /**---------------------------------------------------------------------------
   * 向最顶端历史批次中合并新的历史操作
   * @param historyItem
   */
  this.insertInto = function(historyItem) {
    let head = this.look();
    let temp = head.next;
    head.next = historyItem;
    historyItem.next = temp;
  }

  /**---------------------------------------------------------------------------
   * 撤回到某一步历史
   */
  this.withdrawTo = function(id){
    while (this.look().id!=id){
      this.withdraw(false);
    }
    this.withdraw(true);
  }

  /**---------------------------------------------------------------------------
   * 撤回接口方法
   */
  this.withdraw = function(reshow=true) {
    let historyItem = this.pop();
    withdraw_recursion(historyItem);

    if(reshow){
      context.dataFormatter.formatData();
      context.drawer.drawAll();
      context.simulation.initSimulation();
      context.eventManager.initDefaultEvent();
      context.elementEditor.refreshShow();
    }
  }

  /**---------------------------------------------------------------------------
   * 撤回实现方法
   * @param historyItem
   */
  function withdraw_recursion(historyItem) {
    operationMapFun[historyItem.operation](historyItem);
    if(historyItem.next != null)withdraw_recursion(historyItem.next);
  }

  /**---------------------------------------------------------------------------
   * 开始记录历史操作 直到endRemember之前的操作将被插入当前批次历史记录
   */
  this.startRemember = function() {
    rememberState = rememberStateEnum.START;
  }

  /**---------------------------------------------------------------------------
   * 结束一个批次的历史记录
   */
  this.endRemember = function() {
    rememberState = rememberStateEnum.LEISURE;
  }

  /**---------------------------------------------------------------------------
   * 记录添加节点方法
   * @param addedNode
   */
  this.rememberAddNode = function(addedNode) {
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(this.operationEnum.ADD_NODE, null, addedNode);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录编辑节点方法
   * @param oldNode
   * @param newNode
   */
  this.rememberEditNode = function(oldNode,newNode) {
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(this.operationEnum.EDIT_NODE, oldNode, newNode);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录删除节点操作
   * @param deletedNode
   */
  this.rememberDeleteNode = function(deletedNode) {
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem =new HistoryItem(this.operationEnum.DELETE_NODE, deletedNode, null);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录添加连接操作
   * @param addedLink
   */
  this.rememberAddLink = function(addedLink) {
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(this.operationEnum.ADD_LINK, null, addedLink);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录编辑连接操作
   * @param oldLink
   * @param newLink
   */
  this.rememberEditLink = function(oldLink,newLink){
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(this.operationEnum.EDIT_LINK, oldLink, newLink);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录删除连接操作
   */
  this.rememberDeleteLink = function(deletedLink){
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(context.historyManager.operationEnum.DELETE_LINK, deletedLink, null);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录添加类型
   * @param addedType
   */
  this.rememberAddType = function(addedType) {
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(context.historyManager.operationEnum.ADD_TYPE, null, addedType);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录编辑类型
   * @param oldType
   * @param newType
   */
  this.rememberEditType = function(oldType,newType){
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(this.operationEnum.EDIT_TYPE, oldType, newType);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录删除类型
   * @param deletedLink
   */
  this.rememberDeleteType = function(deletedType){
    if(rememberState===rememberStateEnum.LEISURE) return;
    let historyItem = new HistoryItem(context.historyManager.operationEnum.DELETE_TYPE, deletedType, null);
    rememberHistoryItem(historyItem);
  }

  /**---------------------------------------------------------------------------
   * 记录历史项
   * @param historyItem
   */
  function rememberHistoryItem(historyItem) {
    let _this = context.historyManager;
    if(rememberState===rememberStateEnum.START){
      _this.push(historyItem);
      rememberState = rememberStateEnum.GOING;
    }
    else if(rememberState===rememberStateEnum.GOING) _this.insertInto(historyItem);
    else throw "may fix rememberState illegally."
  }

  /**---------------------------------------------------------------------------
   * 撤回添加节点操作
   * @param historyItem
   */
  function withdrawAddNode(historyItem) {
    let addedNode = historyItem.newObj;
    context.elementEditor.deleteNodeById(addedNode.uuid,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回编辑节点操作
   * @param historyItem
   */
  function withdrawEditNode(historyItem) {
    let oldNode = historyItem.oldObj;
    context.elementEditor.editNode(oldNode,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回删除节点操作
   * @param historyItem
   */
  function withdrawDeleteNode(historyItem) {
    let deletedNode = historyItem.oldObj;
    context.elementEditor.addNode(deletedNode,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回添加连接
   */
  function withdrawAddLink(historyItem) {
    let addedLink = historyItem.newObj;
    context.elementEditor.deleteLinkById(addedLink.uuid,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回编辑连接操作
   * @param historyItem
   */
  function withdrawEditLink(historyItem) {
    let oldLink = historyItem.oldObj;
    context.elementEditor.editLink(oldLink,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回删除连接
   */
  function withdrawDeleteLink(historyItem) {
    let deletedLink = historyItem.oldObj;
    context.elementEditor.addLink(deletedLink,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回添加类型
   */
  function withdrawAddType(historyItem) {
    let addedType = historyItem.newObj;
    context.typeManager.deleteTypeById(addedType.id,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回编辑类型
   * @param historyItem
   */
  function withdrawEditType(historyItem) {
    let oldType = historyItem.oldObj;
    let newType = historyItem.newObj;
    context.typeManager.modifyType(newType,oldType,false,false);
  }

  /**---------------------------------------------------------------------------
   * 撤回删除历史
   * @param historyItem
   */
  function withdrawDeleteType(historyItem) {
    let deletedType = historyItem.oldObj;
    context.typeManager.addType(deletedType,false);
  }

  /**---------------------------------------------------------------------------
   * 通知历史队列的更新
   */
  this.informHistoryUpdate = function(){
    if(context.update == undefined || context.update == null) context.update = {};
    context.update.historyList = new Date().getTime();
  }
}

export function HistoryItem(operation,oldObj,newObj) {
  this.id = Symbol();
  this.operation = operation;
  this.timestamp = new Date().getTime();
  this.next = null;
  this.oldObj = (oldObj==null) ? null : JSON.parse(JSON.stringify(oldObj));
  this.newObj = (newObj==null) ? null : JSON.parse(JSON.stringify(newObj));
}